/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __PQ_DataSerializer_H__
#define __PQ_DataSerializer_H__

#include <string>
#include <vector>

namespace PQCore
{
	//simple data transfer protocal
	enum SerializeDataType
	{
		SerializeDataType_BOOL,
		SerializeDataType_INT,
		SerializeDataType_FLOAT,
		SerializeDataType_DOUBLE,
		SerializeDataType_STRING,
		SerializeDataType_BYTES,//plain binary bytes
	};

	enum SerializeDataId
	{
		SerializeDataId_Unknown,

		SerializeDataId_GameObjectTree,

		SerializeDataId_AssetsArchive,

		SerializeDataId_GPKAsset,
		SerializeDataId_ResourceLocation,

		SerializeDataId_SceneCamera,

		SerializeDataId_PersistProject,
		//NOTE::Above sequence are fixed,New add just above here!!for we serialize data into disk.
	};
	
	/*Serialized datagram send by packet
	*/
	class SerializeDatagram
	{
	public:
		//header contains packet id(int) and packet body length(int)
		enum { HEADER_LENGTH = 8 };

		SerializeDatagram(int count);
		SerializeDatagram(char* data,int count);
		~SerializeDatagram();
		int getId();
		char* data();
		int length();
		char* body();
		//decode header,get body length in bytes
		int getBodyLength();

		void write(int i);
		void write(float f);
		void write(char* buf,int count);

		bool readBool();
		int readInt();
		float readFloat();		
		double readDouble();
		std::string readString(int bytes);
		char* readBytes(int bytes);

	private:
		char* _data;
		int _pos;
		static int _count;//the count of datagrams produces
	};

	/*The serialized data container
	*/
	class SerializeDataParam
	{
	private:
		SerializeDataType _type;//the param type (INT,UTF8_STR,_data,...)
		char* _data;//for _data,all should convert to this
		int _count;

	public:
		SerializeDataParam(bool b);
		SerializeDataParam(int i);	
		SerializeDataParam(float f);
		SerializeDataParam(double d);
		SerializeDataParam(std::string str);
		
		SerializeDataParam(char* bytes,int count);
		~SerializeDataParam();

		inline static bool isBoolParam(SerializeDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==SerializeDataType_BOOL){
					return true;
				}
			}
			return false;
		}

		inline static bool isIntParam(SerializeDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==SerializeDataType_INT){
					return true;
				}
			}
			return false;
		}

		inline static bool isFloatParam(SerializeDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==SerializeDataType_FLOAT){
					return true;
				}
			}
			return false;
		}

		inline static bool isStringParam(SerializeDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==SerializeDataType_STRING){
					return true;
				}
			}
			return false;
		}
		
		SerializeDataType getParamType();
		int getByteCount();
		char* getData();
		
		bool getBool();
		int getInt();
		float getFloat();
		std::string getString();
		
	};

	typedef std::vector<SerializeDataParam*> SerializeDataList;

	/*This class is used to parse serialized data
	*/
	class SerializeParser
	{
	private:
		SerializeDataId _name;
		std::vector<SerializeDataType> paramTypeList;
		std::vector<int> paramByteCountList;
		std::vector<SerializeDataParam*> _paramList;
		int _paramCount;
		int _index;//read index
		SerializeDatagram *_datagram;
		bool _success;//is parse success
	public:
		SerializeDataId getName();
		SerializeDataParam* getParam(int index);
		SerializeDataParam* getParam();
		SerializeParser(SerializeDatagram* datagram);
		SerializeParser(std::string fileName);
		~SerializeParser();

		void parse();

		inline bool success()
		{
			return _success;
		}
	};

	/*This class is used to generate serialized data
	*/
	class SerializeGenerator
	{
	public:
		
	private:
		SerializeDataId _name;
		std::vector<SerializeDataParam*> _paramList;
		int _paramCount;

		int _length;
		SerializeDatagram *_datagram;
	public:
		~SerializeGenerator(void);

		SerializeGenerator(SerializeDataId name);
		void addBoolParam(bool b);
		void addIntParam(int i);
		void addFloatParam(float f);
		void addDoubleParam(double d);
		void addStringParam(std::string str);
		void addBytesParam(char *bytes,int count);

		SerializeDatagram* genDatagram();

		void serialize(std::string fileName);
	};
}
#endif
